﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Common.Entitys.CommonLogs;
using Common.Entitys.Messages;
using Common.Utils;
using Common.Utils.IPCHelps;
using Common.Utlis.Extend;
using Org.BouncyCastle.Utilities.Encoders;

namespace Common.Utlis
{
    /// <summary>
    /// 一个纯粹的TcpServer(接收,发送)
    /// </summary>
    /// <typeparam name="TReceiveMsg"></typeparam>
    /// <typeparam name="TSendMsg"></typeparam>
    public class TcpServerHelp<TReceiveMsg, TSendMsg> : IDisposable
        where TReceiveMsg : BaseBytesMsg
        where TSendMsg : BaseBytesMsg
    {
        private Socket m_SocketClient;

        /// <summary>
        /// 服务的IP
        /// </summary>
        private string m_IP;

        /// <summary>
        /// 服务的端口号
        /// </summary>
        private int m_Port;

        private volatile bool m_IsContinue = true;

        // private volatile int m_TestTimes = 0;

        private bool m_IsReceive = true;

        private bool m_IsSend = true;

        //  private ConcurrentQueue<Byte[]> m_ReceiveBytesCache = new ConcurrentQueue<byte[]>();

        private List<IDisposable> DisposableList = new List<IDisposable>();
        public TcpServerHelp()
        {
            if (typeof(TReceiveMsg) == typeof(BaseBytesMsg))
            {
                m_IsReceive = false;
            }

            if (typeof(TSendMsg) == typeof(BaseBytesMsg))
            {
                m_IsSend = false;
            }

            if (m_IsSend)
            {
                DisposableList.Add(MessageAggregator<TSendMsg>.Subscribe(OnTSendMsg));
            }
        }

        /// <summary>
        /// 接收发送数据的消息(解决偶尔一次断开连接,直接阻塞,加入队列保证可靠)
        /// </summary>
        /// <param name="tSendMsg"></param>
        private void OnTSendMsg(TSendMsg tSendMsg)
        {
            try
            {
                if (m_SocketClient == null)
                {
                    //一会儿重连一下 并记录日志
                    LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 发送时Client为空 ");
                    Thread.Sleep(50);
                    OnTSendMsg(tSendMsg);
                    return;
                }

                if (!m_SocketClient.Connected)
                {
                    //重连一下 并记录日志
                    LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 和Client断开连接 ");
                    Thread.Sleep(50);
                    OnTSendMsg(tSendMsg);
                    return;
                }

                m_SocketClient.Send(tSendMsg.Bytes);
            }
            catch (Exception e)
            {
                //记录异常日志(这里可能是网线断开了,重连一下,当远程主机强迫关闭一个现有连接)
                ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 发生异常");
                LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
                Thread.Sleep(50);
                OnTSendMsg(tSendMsg);
            }

        }

        /// <summary>
        /// 单连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void Init(string ip, int port)
        {
            try
            {
                m_IP = ip;
                m_Port = port;

                IPAddress myIP = IPAddress.Parse(ip);
                IPEndPoint ipEndPoint = new IPEndPoint(myIP, port);
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(100000);
                MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 初始化成功");
                new Task(() =>
                {
                    //等待连接 建立连接
                    m_SocketClient = serverSocket.Accept();
                    while (true)
                    {
                        try
                        {
                            if (!m_SocketClient.Connected)
                            {
                                //断线重连机制
                                MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 断开连接正在尝试重连");
                                LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 断开连接正在尝试重连");
                                m_SocketClient = serverSocket.Accept();
                                MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 重连成功");
                                LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 重连成功");

                            }

                            byte[] receiveBytes = new byte[100000];
                            int length = m_SocketClient.Receive(receiveBytes);
                            if (length == 0)
                            {
                                continue;
                            }
                            byte[] realBytes = receiveBytes.Copy(length);

                            if (m_IsReceive)
                            {
                                TReceiveMsg tReceiveMsg = Activator.CreateInstance<TReceiveMsg>();
                                tReceiveMsg.Bytes = realBytes;
                                MessageAggregator<TReceiveMsg>.Publish(tReceiveMsg);
                            }
                        }
                        catch (Exception ex)
                        {
                            ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 接收数据异常", ex);
                            LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
                        }
                    }
                }).Start();
            }
            catch (Exception e)
            {
                ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 初始化异常", e);
                LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            m_IsContinue = false;
            foreach (IDisposable disposable in DisposableList)
            {
                disposable.Dispose();
            }
            DisposableList.Clear();
        }
    }

    public class TcpServerHelp
    {
        private Socket m_SocketClient;

        /// <summary>
        /// 服务的IP
        /// </summary>
        private string m_IP;

        /// <summary>
        /// 服务的端口号
        /// </summary>
        private int m_Port;

        public Action<Byte[]> ReceiveAction;

        /// <summary>
        /// 是否被连过 连过一次就算 用于区别设备设备不存在和设备断线重连
        /// </summary>
        public volatile bool m_IsAccept = false;

        /// <summary>
        /// 是否发送心跳包
        /// </summary>
        public bool IsSendHeartMsg = false;

        public TcpServerHelp()
        {

        }

        /// <summary>
        /// 接收发送数据的消息(解决偶尔一次断开连接,直接阻塞,加入队列保证可靠)
        /// </summary>
        /// <param name="tSendMsg"></param>
        public void SendBytes(Byte[] bytes, int times = 0, int maxTimes = 10)
        {
            try
            {
                if (!m_IsAccept)
                {
                    return;
                }

                if (times > maxTimes)
                {
                    LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP：{m_IP}  端口号：{m_Port} 连续发送{maxTimes}次失败 原因未知 {Hex.ToHexString(bytes)}");
                    return;
                }

                if (m_SocketClient == null)
                {
                    //一会儿重连一下 并记录日志
                    LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 发送时Client为空 ");
                    Thread.Sleep(50);
                    SendBytes(bytes, ++times);
                    return;
                }

                if (!m_SocketClient.Connected)
                {
                    //重连一下 并记录日志
                    LogHelp.AddLog<WarnLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 和Client断开连接 ");
                    Thread.Sleep(50);
                    SendBytes(bytes, ++times);
                    return;
                }

                int length = bytes.Length;
                int sendLength = m_SocketClient.Send(bytes);
                if (length != sendLength)
                {
                    byte[] lastBytes = bytes.Copy(sendLength, length - sendLength);
                    //发送剩余的Byte
                    SendBytes(lastBytes, times);
                }
            }
            catch (Exception e)
            {
                //记录异常日志(这里可能是网线断开了,重连一下,当远程主机强迫关闭一个现有连接)
                ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 发生异常");
                LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
                Thread.Sleep(50);
                SendBytes(bytes, ++times);
            }

        }




        /// <summary>
        /// 单连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void Init(string ip, int port)
        {
            try
            {
                m_IP = ip;
                m_Port = port;
                IPAddress myIP = IPAddress.Parse(ip);
                IPEndPoint ipEndPoint = new IPEndPoint(myIP, port);
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //加入销毁
                DisposeMsg dispose = new DisposeMsg(serverSocket);
                MessageAggregator<DisposeMsg>.Publish(dispose);
                serverSocket.Bind(ipEndPoint);
                serverSocket.NoDelay = true;//发送不延时,从发送上解决粘包的问题
                serverSocket.Listen(100000);
                MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 初始化成功");
                new Task(() =>
                {
                    //等待连接 建立连接
                    m_SocketClient = serverSocket.Accept();
                    m_SocketClient.NoDelay = true;//发送不延时,从发送上解决粘包的问题
                    m_IsAccept = true;
                    if (m_Port == 7000)
                    {
                        MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 连上了");
                        LogHelp.AddLog<InitLogEntity>($"TCP服务器 IP:{m_IP} 端口{m_Port} 连上了");
                    }
                    while (true)
                    {
                        try
                        {
                            if (!m_SocketClient.Connected)
                            {
                                //断线重连机制
                                LogHelp.AddLog<WarnLogEntity>($"检测到客户端断开 TCP服务器 IP:{m_IP} 端口{m_Port} 的连接");
                                m_SocketClient = serverSocket.Accept();
                                m_SocketClient.NoDelay = true;//发送不延时,从发送上解决粘包的问题
                                LogHelp.AddLog<WarnLogEntity>($"检测到客户端重新连接 TCP服务器 IP:{m_IP} 端口{m_Port} ");
                            }

                            byte[] receiveBytes = new byte[100000];

                            // 将数据写入receiveBytes
                            int length = m_SocketClient.Receive(receiveBytes);

                            if (length == 0 || null == ReceiveAction)
                            {
                                //发送心跳包
                                if (IsSendHeartMsg)
                                {
                                    SendHeartMsg();
                                } 
                                continue;
                            }
                            byte[] realBytes = receiveBytes.Copy(length);

                            // test print
                            receiveBytes.Print();

                            ReceiveAction.Invoke(realBytes);
                        }
                        catch (Exception ex)
                        {
                            ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 接收数据异常", ex);
                            LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
                        }
                    }
                }).Start();
            }
            catch (Exception e)
            {
                ErrorLogEntity errorLogEntity = new ErrorLogEntity($"TCP服务器 IP:{m_IP} 端口{m_Port} 初始化异常", e);
                LogHelp.AddLog<ErrorLogEntity>(errorLogEntity);
                MessageAggregator<PromptMsg>.Publish($"TCP服务器 IP:{m_IP} 端口{m_Port} 初始化异常 {e.Message}");
            }
        }

        /// <summary>
        /// 发送心跳包
        /// </summary>
        private void SendHeartMsg()
        {
            IPCMsg ipcMsg = new IPCMsg(new HeartMsg());
            byte[] bytes = IPCCommon.GetEntityByte(ipcMsg);
            SendBytes(bytes, 0, 1);
        }



    }

    /// <summary>
    /// 心跳包
    /// </summary>
    [Serializable]
    public class HeartMsg
    {

    }
}
